﻿using System;
using System.Collections.Generic;
using System.Reflection;
using GameFramework.common;
using GameFramework.net.attributes;
using GameFramework.net.msgserializer;
using GameFramework.scripts;
using UnityEngine;

namespace GameFramework.net
{
    public class MsgManager:Singleton<MsgManager>
    {
        //消息id和消息类型的映射
        private Dictionary<int, Type> msgId2Type = new Dictionary<int, Type>();
        private Dictionary<Type, int> msgType2Id = new Dictionary<Type, int>();
        
        private Dictionary<Type, IScript> msgType2Script = new Dictionary<Type, IScript>();
        
        //所有的消息序列化器
        private List<MsgSerializer> msgSerializers = new List<MsgSerializer>();

        //加载消息类型，消息处理脚本，消息序列化器
        public void loadMsgTypes_MsgScripts_MsgSerializers()
        {
            
            Type[] types = Assembly.GetExecutingAssembly().GetTypes();
            foreach (Type type in types)
            {
                if (type.IsInterface)
                {
                    continue;
                }
                parserMsg(type);
                parserMsgSerializer(type);
            }
            foreach (Type type in types)
            {
                if (type.IsInterface)
                {
                    continue;
                }
                parserMsgScript(type);
            }
        }

        private void parserMsgSerializer(Type type)
        {
            if (!typeof(MsgSerializer).IsAssignableFrom(type))
            {
                return;
            }
            MsgSerializer msgSerializer = (MsgSerializer)Activator.CreateInstance(type);
            msgSerializers.Add(msgSerializer);
        }

        private void parserMsgScript(Type type)
        {
            MsgScriptAttribute msgScriptAttribute = type.GetCustomAttribute<MsgScriptAttribute>();
            if (msgScriptAttribute == null)
            {
                return;
            }
                
            Type msgType = msgScriptAttribute.msgType;
            if (!msgType2Id.ContainsKey(msgType))
            {
                Debug.LogError("未找到消息处理脚本对应的消息类型："+msgType.Name);
                return;
            }

            if (msgType2Script.ContainsKey(msgType))
            {
                //消息对应的消息处理脚本已经存在了，一个消息只能右一个消息处理脚本
                Debug.LogError("消息类型："+msgType.Name+"已经存在消息处理脚本:"+msgType2Script[msgType].GetType().Name+
                               "  新发现消息处理脚本:"+type.Name);
                return;
            }

            if (!typeof(IScript).IsAssignableFrom(type))
            {
                Debug.LogError("消息类型："+msgType.Name+"已经存在消息处理脚本:"+msgType2Script[msgType].GetType().Name+
                               "  未实现IScript接口！");
                return;
            }

            msgType2Script.Add(msgType,(IScript)Activator.CreateInstance(type));
        }

        private void parserMsg(Type type)
        {
            MsgAttribute msgAttribute = type.GetCustomAttribute<MsgAttribute>();
            if (msgAttribute == null)
            {
                return;
            }
                
            string name = type.Name;
            int id = getHashId(name);
            if (msgId2Type.ContainsKey(id))
            {
                //TODO 打印消息重复
                return;
            }
            msgId2Type.Add(id,type);
            msgType2Id.Add(type,id);
        }

        public byte[] serializeMsg(MsgSerializeType serializeType,object msg)
        {
            foreach (MsgSerializer msgSerializer in msgSerializers)
            {
                if (msgSerializer.canSerialize(serializeType))
                {
                    try
                    {
                        return msgSerializer.Serialize(msg);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("序列化失败："+e);
                    }

                }
            }

            return null;
        }
        
        public object deSerializeMsg(MsgSerializeType serializeType,byte[] msg,Type msgType)
        {
            foreach (MsgSerializer msgSerializer in msgSerializers)
            {
                if (msgSerializer.canSerialize(serializeType))
                {
                    try
                    {
                        return msgSerializer.Deserialize(msg,msgType);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("反序列化失败："+e);
                    }

                }
            }

            return null;
        }

        public IScript getMsgScript(Type type)
        {
            if (msgType2Script.ContainsKey(type))
            {
                return msgType2Script[type];
            }

            return null;
        }

        public int getMsgId(Type msgType)
        {
            if (msgType2Id.ContainsKey(msgType))
            {
                return msgType2Id[msgType];
            }

            return -1;
        }
        public Type getMsgType(int msgId)
        {
            if (msgId2Type.ContainsKey(msgId))
            {
                return msgId2Type[msgId];
            }

            return null;
        }

        private int getHashId(string value)
        {
            int h = 0;
            if (h == 0 && value.Length > 0) {
                char[] val = value.ToCharArray();

                for (int i = 0; i < value.Length; i++) {
                    h = 31 * h + val[i];
                }
            }
            return h;
        }
    }
}